package com.xbongbong.pro.service.market.statistics.impl;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.service.market.statistics.Contract4StaticHandle;
import com.xbongbong.saas.domain.entity.StaticForMarketActivityEntity;
import com.xbongbong.saas.domain.entity.StaticForMarketUpdateEntity;
import com.xbongbong.saas.domain.entity.StaticForUpdateDTO;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.model.MarketActivityForStaticModel;
import com.xbongbong.saas.model.MarketActivityModel;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @Auther: yingjianfeng
 * @Date: 2022/3/15 14:43
 * @Description:
 */
@Slf4j
@Service("contract4StaticHandle")
public class Contract4StaticHandleImpl extends AbstractMarketActivity4StaticHandle implements Contract4StaticHandle {
    @Resource
    private MarketActivityForStaticModel marketActivityForStaticModel;
    @Resource
    private MarketActivityModel marketActivityModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private EsHelper esHelper;

    @Override
    public Integer type() {
        return XbbRefTypeEnum.CONTRACT.getCode();
    }

    @Override
    @Async("staticsMarketData")
    public void add(PaasFormDataEntity paasFormDataEntity) throws XbbException {
        try {
            Long id = paasFormDataEntity.getId();
            String corpid = paasFormDataEntity.getCorpid();
            JSONObject data = paasFormDataEntity.getData();
            StaticForMarketActivityEntity addEntity = new StaticForMarketActivityEntity();
            addEntity.setCorpid(corpid);
            StaticForMarketActivityEntity updateEntity = new StaticForMarketActivityEntity();
            updateEntity.setCorpid(corpid);
            List<StaticForMarketActivityEntity> addEntitys = new ArrayList<>();
            List<StaticForMarketActivityEntity> updateEntitys = new ArrayList<>();
            List<Long> delIds = new ArrayList<>();
            // 合同关联客户id
            Long linkCustomerId = data.getLong(ContractEnum.LINK_CUSTOMER.getAttr());
            // 合同关联机会id
            Long linkOpportunityId = data.getLong(ContractEnum.LINK_OPPORTUNITY.getAttr());
            if (Objects.isNull(linkCustomerId) && Objects.isNull(linkOpportunityId)) {
                return;
            }
            // 为空 则可以判断 此合同订单是由客户创建过来的
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("corpid", corpid);
            params.put("del", 0);
            params.put("customerId", linkCustomerId);
            List<StaticForMarketActivityEntity> customerIdNoDeduplication = marketActivityForStaticModel.findEntitys(params);
            if (CollectionsUtil.isEmpty(customerIdNoDeduplication)) {
                // 此客户不是由市场活动建线索转客户而来 无需处理
                return;
            }
            int isUpdate = 0;
            for (StaticForMarketActivityEntity staticForMarketActivityEntity : customerIdNoDeduplication) {
                if (Objects.isNull(staticForMarketActivityEntity.getContractId()) && Objects.isNull(staticForMarketActivityEntity.getSaleOpportunityId())) {
                    isUpdate = 1;
                    break;
                }
            }
            // 客户没建过机会
            if (isUpdate == 1) {
                updateEntity = customerIdNoDeduplication.get(0);
                // 理论上只有一个记录的 不需要循环
                updateEntity.setContractId(paasFormDataEntity.getDataId());
                updateEntity.setContractMoney(data.getDouble(ContractEnum.AMOUNT.getAttr()));
                updateEntitys.add(updateEntity);
            } else {
                addEntity = customerIdNoDeduplication.get(0);
                addEntity.setId(null);
                addEntity.setSaleOpportunityId(null);
                addEntity.setSaleMoney(null);
                addEntity.setSaleStage(null);
                addEntity.setContractId(paasFormDataEntity.getDataId());
                addEntity.setContractMoney(data.getDouble(ContractEnum.AMOUNT.getAttr()));
                addEntitys.add(addEntity);
            }

            // 插入新数据
            if (CollectionsUtil.isNotEmpty(addEntitys)) {
                marketActivityForStaticModel.insertBatch(addEntitys, corpid);
            }
            if (CollectionsUtil.isNotEmpty(updateEntitys)) {
                marketActivityForStaticModel.updateBatchForStatic(updateEntitys);
            }
        } catch (XbbException e) {
            log.error("com.xbongbong.pro.service.marketActivity4Static.MarketActivity4StaticHandle.add ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    @Override
    @Async("staticsMarketData")
    public void update(PaasFormDataEntity paasFormDataEntity) throws XbbException {
        try {
            String corpid = paasFormDataEntity.getCorpid();
            JSONObject data = paasFormDataEntity.getData();
            Boolean flag = false;
            List<StaticForMarketUpdateEntity> listEntitys = new ArrayList<>();
            IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_STATICS_MARKET_DATA;
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
            boolQueryBuilder.filter(termQuery("contractId", paasFormDataEntity.getDataId()));
            flag = updateContract4MarketActivity(corpid, data, flag, indexTypeEnum, listEntitys, boolQueryBuilder, paasFormDataEntity);
            if (flag && CollectionsUtil.isNotEmpty(listEntitys)) {
                // 可能需要改动, listEntitys可能数量有点多
                marketActivityForStaticModel.updateBatch(listEntitys, corpid);
            }
        } catch (XbbException e) {
            log.error("com.xbongbong.pro.service.marketActivity4Static.MarketActivity4StaticHandle.update ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    @Override
    @Async("staticsMarketData")
    public void updateBatch(List<StaticForUpdateDTO> list, String corpid) throws XbbException {
        // 批量编辑不支持合同金额修改
    }

    @Override
    @Async("staticsMarketData")
    public void deleteBatch(List<Long> idIn, String corpid, Integer del) throws XbbException {
        try {
            if (idIn.size() == 0) {
                return;
            }
            List<Long> delIds = new ArrayList<>();
            IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_STATICS_MARKET_DATA;
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            // 这里暂不处理这个del条件
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
            List<StaticForMarketActivityEntity> staticList = new ArrayList<>();
            long count;
            // fix: 2022/3/7 处理合同
            boolQueryBuilder.filter(termsQuery("contractId", idIn));
            sourceBuilder.query(boolQueryBuilder);
            searchRequest.source(sourceBuilder);
            count = xbbElasticsearchRestTemplate.count(searchRequest, PaasFormDataEntityExt.class);
            Map<Long, StaticForMarketActivityEntity> entityMap = getMarketEntity(idIn, "contractId", corpid);
            Set<Long> customerIdIn = new HashSet<>();
            if (count > 0) {
                getDelIds(delIds, sourceBuilder, searchRequest, count, customerIdIn);
            } else {
                return;
            }
            // 判断是否需要新建一个对应的staticMarketEntity
            List<Long> flag2AddNewData = getFlag2AddNewData(entityMap.keySet(), count, "marketId", corpid, "marketId");
            //List<Long> flag2AddNewData = getFlag2AddNewData(customerIdIn, corpid);
            if (flag2AddNewData.size() > 0) {
                // 因为是批量删除   可能会删不同市场活动的合同
                for (Long marketId : flag2AddNewData) {
                    StaticForMarketActivityEntity contractStaticForMarketActivityEntity = entityMap.get(marketId);
                    if(Objects.nonNull(contractStaticForMarketActivityEntity)){
                        contractStaticForMarketActivityEntity.setDataId(null);
                        contractStaticForMarketActivityEntity.setId(null);
                        contractStaticForMarketActivityEntity.setContractId(null);
                        contractStaticForMarketActivityEntity.setContractMoney(null);
                        staticList.add(contractStaticForMarketActivityEntity);
                    }
                }
            }
            if (delIds.size() > 0) {
                // 可能需要改动, listEntitys可能数量有点多
                marketActivityForStaticModel.deleteBatch(delIds, corpid, del);
            }
            if (staticList.size() > 0) {
                marketActivityForStaticModel.insertBatch(staticList, corpid);
            }
        } catch (XbbException e) {
            log.error("com.xbongbong.pro.service.marketActivity4Static.MarketActivity4StaticHandle.deleteBatch ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    /**
     * 此方法仅供刷脚本同步合同使用，切上线时使用，后续废弃禁止使用
     * date: 2022/3/17 10:49 上午
     *
     * @author yingjf
     */
    @Override
    public void addBatchContractByScript(String corpid, List<PaasFormDataEntity> list, List<StaticForMarketActivityEntity> customerIdNoDeduplication) throws XbbException {
        try {
            List<StaticForMarketActivityEntity> addEntitys = new ArrayList<>();
            List<StaticForMarketActivityEntity> updateEntitys = new ArrayList<>();
            // 遍历需要处理的合同
            HashSet<Long> updateKeySet = new HashSet<>();
            for (PaasFormDataEntity temp : list) {
                StaticForMarketActivityEntity addEntity = new StaticForMarketActivityEntity();
                addEntity.setCorpid(corpid);
                StaticForMarketActivityEntity updateEntity = new StaticForMarketActivityEntity();
                updateEntity.setCorpid(corpid);
                JSONObject data = temp.getData();
                // 合同关联客户id
                Long linkCustomerId = data.getLong(ContractEnum.LINK_CUSTOMER.getAttr());
                int isUpdate = 0;
                StaticForMarketActivityEntity tamplatEntity = null;
                for (StaticForMarketActivityEntity staticForMarketActivityEntity : customerIdNoDeduplication) {
                    Long customerId = staticForMarketActivityEntity.getCustomerId();
                    if (!Objects.equals(customerId, linkCustomerId)) {
                        continue;
                    } else {
                        tamplatEntity = staticForMarketActivityEntity;
                    }
                    if (Objects.isNull(staticForMarketActivityEntity.getContractId())
                            && Objects.isNull(staticForMarketActivityEntity.getSaleOpportunityId())
                            && !updateKeySet.contains(staticForMarketActivityEntity.getId())
                    ) {
                        // fix 加个hashSet，存放市场活动图表主键ID，如果hashSet中不存在这个id，则可以更新
                        isUpdate = 1;
                        tamplatEntity = staticForMarketActivityEntity;
                        updateKeySet.add(staticForMarketActivityEntity.getId());
                        break;
                    }
                }
                if (Objects.isNull(tamplatEntity)) {
                    continue;
                }
                // 客户没建过机会
                if (isUpdate == 1) {
                    // fix 如果一个客户下面有多个合同，会出现只更新一条，但是没插入其他合同的数据
                    BeanUtils.copyProperties(tamplatEntity, updateEntity);
                    // 理论上只有一个记录的 不需要循环
                    updateEntity.setContractId(temp.getDataId());
                    updateEntity.setContractMoney(data.getDouble(ContractEnum.AMOUNT.getAttr()));
                    updateEntitys.add(updateEntity);
                } else {
                    BeanUtils.copyProperties(tamplatEntity, addEntity);
                    addEntity.setId(null);
                    addEntity.setSaleOpportunityId(null);
                    addEntity.setSaleMoney(null);
                    addEntity.setSaleStage(null);
                    addEntity.setContractId(temp.getDataId());
                    addEntity.setContractMoney(data.getDouble(ContractEnum.AMOUNT.getAttr()));
                    addEntitys.add(addEntity);
                }
            }
            // 插入新数据
            if (CollectionsUtil.isNotEmpty(addEntitys)) {
                marketActivityForStaticModel.insertBatch(addEntitys, corpid);
            }
            if (CollectionsUtil.isNotEmpty(updateEntitys)) {
                marketActivityForStaticModel.updateBatchForStatic(updateEntitys);
            }
        } catch (XbbException e) {
            log.error("com.xbongbong.pro.service.marketActivity4Static.MarketActivity4StaticHandle.addBatchContractByScript ", e);
            // 外面捕获
            throw e;
        }
    }

    /**
     * 更新合同时 是否需要更新中间表
     * date: 2022/3/7 10:35 上午
     *
     * @author yingjf
     */
    private Boolean updateContract4MarketActivity(String corpid, JSONObject data, Boolean flag, IndexTypeEnum indexTypeEnum, List<StaticForMarketUpdateEntity> listEntitys, BoolQueryBuilder boolQueryBuilder, PaasFormDataEntity paasFormDataEntity) throws XbbException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        sourceBuilder.query(boolQueryBuilder);
        searchRequest.source(sourceBuilder);
        //fix 这里应该不需要遍历，根据合同id可以锁定一条数据
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 100);
        XbbAggregatedPage<StaticForMarketActivityEntity> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, StaticForMarketActivityEntity.class);
        List<StaticForMarketActivityEntity> content = esEntities.getContent();
        if(CollectionsUtil.isEmpty(content)){
            return false;
        }
        StaticForMarketActivityEntity entity = content.get(0);
        StaticForMarketUpdateEntity staticForMarketUpdateEntity = new StaticForMarketUpdateEntity();
        staticForMarketUpdateEntity.setCorpid(corpid);
        // 修改合同金额时 需要改中间表
        if (!Objects.equals(entity.getContractMoney(), data.getDouble(ContractEnum.AMOUNT.getAttr()))) {
            flag = true;
            staticForMarketUpdateEntity.setContractMoney(data.getDouble(ContractEnum.AMOUNT.getAttr()));
        }
        if (flag) {
            staticForMarketUpdateEntity.setId(entity.getDataId());
            listEntitys.add(staticForMarketUpdateEntity);
        }
        return flag;
    }

}
